#ifndef __SLOTHTTPD_HTTP_CONNECTION_HPP__
#define __SLOTHTTPD_HTTP_CONNECTION_HPP__

#include <slothttpd/http/request.hpp>
#include <slothttpd/http/response.hpp>
#include <slothttpd/http/status.hpp>
#include <slothttpd/generic_pool.hpp>
#include <slothttpd/stage/receive_request.hpp>
#include <slothttpd/data_buffer.hpp>

#include <utility>

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/intrusive/list.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/scoped_array.hpp>
#include <boost/noncopyable.hpp>
#include <boost/system/error_code.hpp>

namespace slothttpd {

typedef boost::asio::ip::tcp::socket            stream_socket;

class connection :
    public boost::noncopyable,
    public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink> >
{
    friend void intrusive_ptr_add_ref(connection*) noexcept;
    friend void intrusive_ptr_release(connection*) noexcept;
public:
    static void close_all() noexcept;

    connection(boost::asio::io_service& ios);
    
    // safe to call few times
    void close() noexcept;
    void shutdown();
    void gracefull_shutdown();
    
    void start();
    
    void send_stock_response(const http::status::status_type &status) noexcept;
    
    template<typename Handler>
    void post_write_responce(Handler handler)
    {
        auto buffs = responce.get_buffers_range();
        
        boost::asio::async_write(socket, 
                                 buffs,
                                 boost::asio::transfer_exactly(boost::asio::buffer_size(buffs)),
                                 handler);
    }
    
private:
    static void handle_send_stock_response(connection_ptr c, const boost::system::error_code &err);
    
public:
    generic_pool                    pool;
    stream_socket                   socket;
    
    http::request                   request;
    http::response                  responce;
    
    receive_buffer_list             receive_buffers;
    
    unsigned long                   requests_processed;
    
public:
    static unsigned long            current_connections;
    static unsigned long            max_connections;
    static unsigned long            total_requests;
    
private:
    unsigned long                   ref_count_;

private:
    typedef boost::intrusive::list<connection, boost::intrusive::constant_time_size<false> >
        connection_list_t;
    
    static connection_list_t        connection_list;
};

} // namespace slothttpd

#endif
